/**
 * 
 */
package de.cbf.cam.dsa.tavern.carte.model.persistence;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;

import de.cbf.cam.dsa.tavern.carte.Activator;
import de.cbf.cam.dsa.tavern.carte.model.persistence.exceptions.PersistenceLoadException;
import de.cbf.cam.dsa.tavern.carte.model.persistence.exceptions.PersistenceSaveException;
import de.cbf.cam.dsa.tavern.carte.model.persistence.ui.CompositeFileConfig;

/**
 * @author Stefan Alter
 *
 */
public abstract class PersisterAbstractXML extends PersisterAbstract {
		
	private String xmlFileName = "";
	private CompositeFileConfig compositeConfig;	
	
	public PersisterAbstractXML() {		
		IPreferenceStore store = Activator.getDefault().getPreferenceStore();
		xmlFileName = store.getString(getPreferenceNameOfFileName());
	}

	

	protected abstract String 	getFileDialogText();
	/**
	 * always set identifying extension to position 0
	 * @return
	 */
	protected abstract String[] getFilterExtensions(); 
	protected abstract String[] getFilterNames();
	
	protected abstract String getPreferenceNameOfFileName();
	
	
	@Override
	public void setViewParent(Composite parent) {
		if(compositeConfig != null){
			deRegisterListeners();
		}
		compositeConfig = new CompositeFileConfig(parent, SWT.NONE);
		compositeConfig.setLayoutData(new GridData(GridData.FILL_BOTH));
		compositeConfig.setFileName(xmlFileName);
		//
		registerListeners();
	}	
	
	private void deRegisterListeners() {
		compositeConfig.deRegisterChangeFileNameListener(changeFileName);		
		compositeConfig.deRegisterSaveFileListener(saveXMLFile);		
//		compositeConfig.deRegisterOpenFileListener(openXMLFile);
	}

	private void registerListeners() {
		compositeConfig.registerChangeFileNameListener(changeFileName);		
		compositeConfig.registerSaveFileListener(saveXMLFile);		
//		compositeConfig.registerOpenFileListener(openXMLFile);
	}

	@Override
	public void config() {		
		//generate shell
		Shell shell = new Shell(compositeConfig.getShell(),SWT.OPEN|SWT.APPLICATION_MODAL);
		//open OpenFile dialog
		FileDialog fd = new FileDialog(shell, SWT.OPEN);			
	    fd.setText(getFileDialogText());
	    fd.setFilterPath(getPath());	        
	    fd.setFilterExtensions(getFilterExtensions());
	    fd.setFilterNames(getFilterNames());
	    String fileName = fd.open();
	    if(fileName != null){
	    	String extension = getFilterExtensions()[0].substring(1);
	    	if( ! fileName.endsWith(extension)){
	    		//if user forgot to add extension
	    		fileName = fileName + extension;
	    	}
	    	setXmlFileName(fileName);	    	
	    }	
	    //load when opened
	    loadEntityObjects();
	}

	
	private String getPath() {
		String path ="";
		int index = xmlFileName.lastIndexOf("\\");
		path =xmlFileName.substring(0,index);
		return path;
	}

	public String getXmlFileName() {
		return xmlFileName;
	}

	public void setXmlFileName(String xmlFileName) {
		if(xmlFileName == null || xmlFileName.equals(this.xmlFileName))return;		
		this.xmlFileName = xmlFileName;
		if(compositeConfig != null){
			compositeConfig.setFileName(xmlFileName);
		}		
		IPreferenceStore store = Activator.getDefault().getPreferenceStore(); 
		store.setValue(getPreferenceNameOfFileName(),xmlFileName);
		//create file if not exists
		File file = new File(xmlFileName);
		try {
			boolean newlyCreated = file.createNewFile(); 
			if(newlyCreated){
				//create normal header to not run into exception when trying to read
				FileOutputStream outStream = null;
				XMLEncoder encoder = null;				
				outStream = new FileOutputStream(xmlFileName);
				encoder = new XMLEncoder(outStream);							
				encoder.close();
				outStream.close();
			}			
		} catch (IOException e) {
			e.printStackTrace();			
		}		
		setUnsavedChanges(true);
	}
	
	
	@Override
	protected Collection<Object> doLoadObjects() throws PersistenceLoadException {
		Collection<Object> loads = new ArrayList<Object>();
		XMLDecoder decoder = null;
		FileInputStream inputStream = null;
		try {
			inputStream = new FileInputStream(xmlFileName);			
			decoder = new XMLDecoder(inputStream);			
			while(true){	//TODO (Later) rework for DocumentHandler
				Object obj = decoder.readObject();
				loads.add(obj);									
			}
		} catch (NoSuchElementException e) {	
			//file is completly empty			
		} catch (IndexOutOfBoundsException e) {	
			//goes here if no elements in stream anymore
		} catch (IOException e) {
			throw new PersistenceLoadException(e);
		}finally{
			if(decoder != null){
				decoder.close();
			}
			if(inputStream != null){
				try {
					inputStream.close();
				} catch (IOException e) {			
				};
			}		
		}
		return loads;
	}	
	
	@Override
	protected boolean doSaveObjects() throws PersistenceSaveException {
		boolean success = false;		
		try {
			FileOutputStream outStream = new FileOutputStream(xmlFileName);
			XMLEncoder encoder = new XMLEncoder(outStream);
			Iterator<Object> iterator = getObjects().iterator();
			while (iterator.hasNext()) {
				Object object = (Object) iterator.next();
				encoder.writeObject(object);	
			}				
			encoder.close(); 
			success = true;
		} catch (FileNotFoundException e) {
			throw new PersistenceSaveException(e);			
		}		
		return success;
	}
	
	@Override
	public void setUIUnsavedChanges(boolean unsavedChanges) {
		if(compositeConfig != null){
			compositeConfig.setButtonSaveEnbaled(unsavedChanges);
		}				
	}
	
	private ChangeXMLFileName changeFileName = new ChangeXMLFileName();
	private class ChangeXMLFileName implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent arg0) {
			config();					
		}		
	}
	
//	private OpenXMLFile openXMLFile = new OpenXMLFile();
//	private class OpenXMLFile implements ActionListener{
//		@Override
//		public void actionPerformed(ActionEvent arg0) {
//			loadObjects();			
//		}		
//	}
	private SaveXMLFile saveXMLFile = new SaveXMLFile();
	private class SaveXMLFile implements ActionListener{
		@Override
		public void actionPerformed(ActionEvent arg0) {
			saveObjects();			
		}		
	}
	

}
